package com.liang.blog.system.service.impl;

import com.liang.blog.model.BlogMenu;
import com.liang.blog.model.constant.SecurityConstants;
import com.liang.blog.security.utils.BlogSecurityUtil;
import com.liang.blog.vo.menu.*;
import com.liang.blog.system.mapper.BlogMenuMapper;
import com.liang.blog.system.service.BlogMenuService;
import com.liang.blog.vo.user.LoginUserVo;
import org.apache.commons.beanutils.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.lang.reflect.InvocationTargetException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author：YanWenLiang
 * @Date:2023-08-17-16:52
 */
@Service
public class BlogMenuServiceImpl implements BlogMenuService {

    @Autowired
    private BlogMenuMapper blogMenuMapper;

    /**
     * 根据父 id 获取菜单信息
     *
     * @param uid
     * @return
     */
    @Override
    public List<BlogMenu> getBlogMenuByUid(Long uid) {
        return blogMenuMapper.getBlogMenuByParentId(uid);
    }

    /**
     * 根据父 id 获取信息(作用于删除菜单)
     * @param uid
     * @return
     */
    @Override
    public List<BlogMenu> getBlogMenuByParentIdToDelete(Long uid) {
        return blogMenuMapper.getBlogMenuByParentIdToDelete(uid);
    }


    /**
     * 通过角色菜单中间表，获取菜单信息
     *
     * @param roleId
     */
    @Override
    public List<MenuPermissionVo> getMenuByRoleIdAndMenuId(int roleId) {
        return blogMenuMapper.getMenuByRoleIdAndMenuId(roleId);
    }

    /**
     * 转换成前端路由
     *
     * @param menuList
     * @return
     */
    @Override
    public List<RouterVo> buildRouter(List<BlogMenu> menuList) {
//        // 菜单结果集，用于判断父子关系
//        Map<Long, BlogMenu> menuMap = new HashMap<>(16);
        // 路由结果集，同步子路由
        Map<Long, RouterVo> routerMap = new HashMap<>(16);
        // 最终结果
        List<RouterVo> result = new ArrayList<>();
        // 保证根节点在集合最前
        for (BlogMenu rootBlogMenu : menuList) {
            // 解析当前节点是否有子节点
            if (!routerMap.containsKey(rootBlogMenu.getId())) {
//                menuMap.put(rootBlogMenu.getId(), rootBlogMenu);
                // 同时记录子节点路由
                routerMap.put(rootBlogMenu.getId(), initRouterVo(rootBlogMenu));
            }
            // 将根节点记录进结果集
            if (rootBlogMenu.getParentId().intValue() == 0) {
                result.add(routerMap.get(rootBlogMenu.getId()));
                continue;
            }
            RouterVo routerVo = routerMap.get(rootBlogMenu.getParentId());
            if (!ObjectUtils.isEmpty(routerVo)) {
                // 子路由添加
                routerVo.getChildren().add(routerMap.get(rootBlogMenu.getId()));
                routerVo.setAlwaysShow(true);
            }
        }
        return result;
    }

    /**
     * 获取全部类型为目录和菜单的菜单
     * @return
     */
    @Override
    public List<BlogMenu> getMenuAll() {
        return blogMenuMapper.getMenuAll();
    }

    /**
     * 通过父id获取
     *
     * @param parentId
     * @return
     */
    @Override
    public List<BlogMenuVo> getBlogMenuAllByParentId(Long parentId) {
        List<BlogMenuVo> blogMenuList = blogMenuMapper.getBlogMenuAllByParentId(parentId);
        List<Long> menuIds = blogMenuList.stream().map(BlogMenu::getId).collect(Collectors.toList());
        Map<Long, Boolean> map = this.hasChildrenData(menuIds);

        blogMenuList.forEach(blogMenuVo -> blogMenuVo.setHasChildren(map.get(blogMenuVo.getId())));

        return blogMenuList;
    }

    /**
     * 构建树状菜单结构
     * @param blogMenuSearch
     * @return
     */
    public List<BlogMenu> buildMenu(BlogMenu blogMenuSearch) {
        List<BlogMenu> blogMenuList = blogMenuMapper.getBlogMenuList(blogMenuSearch);

        if (blogMenuList == null || blogMenuList.size() == 0){
            return null;
        }
        List<Long> ids = blogMenuList.stream().map(BlogMenu::getParentId).collect(Collectors.toList());
        Long minId = Collections.min(ids);

        Map<Long, BlogMenu> blogMap = new HashMap();
        List<BlogMenu> result = new ArrayList<>();

        for (BlogMenu rootBlogMenu : blogMenuList) {
            if (!blogMap.containsKey(rootBlogMenu.getId())) {
                blogMap.put(rootBlogMenu.getId(), rootBlogMenu);
            }

            if (rootBlogMenu.getParentId().intValue() == minId) {
                result.add(rootBlogMenu);
                continue;
            }

            BlogMenu blogMenu = blogMap.get(rootBlogMenu.getParentId());
            if (!ObjectUtils.isEmpty(blogMenu)) {
                blogMenu.getChildren().add(rootBlogMenu);
            }

        }

        return result;
    }


    /**
     * 保存菜单
     *
     * @param blogMenu
     * @return
     */
    @Override
    public int insertMenu(BlogMenu blogMenu) {
        LoginUserVo loginUserVo = BlogSecurityUtil.get(SecurityConstants.LOGIN_USER, LoginUserVo.class);
        blogMenu.setCreateBy(loginUserVo.getUsername());
        return blogMenuMapper.insertMenu(blogMenu);
    }

    /**
     * 获取全部菜单信息，（id, parent_id, menu_name）
     *
     * @return
     */
    @Override
    public List<MenuSelectVo> getBlogMenuAll() {
        List<BlogMenu> blogMenuAll = blogMenuMapper.getBlogMenuAll();
        Map<Long, MenuSelectVo> menuSelectVoMap = new HashMap<>();
        List<MenuSelectVo> result = new ArrayList<>();
        for (BlogMenu rootBlogMenu : blogMenuAll) {
            if (!menuSelectVoMap.containsKey(rootBlogMenu.getId())) {
                menuSelectVoMap.put(rootBlogMenu.getId(), this.buildMenuSelectVo(rootBlogMenu));
            }

            if (rootBlogMenu.getParentId().intValue() == 0) {
                result.add(menuSelectVoMap.get(rootBlogMenu.getId()));
                continue;
            }

            MenuSelectVo selectVo = menuSelectVoMap.get(rootBlogMenu.getParentId());
            if (!ObjectUtils.isEmpty(selectVo)) {
//                menuSelectVoMap.get()
                selectVo.getChildren().add(menuSelectVoMap.get(rootBlogMenu.getId()));
            }

        }
        return result;
    }

    /**
     * 修改菜单信息
     *
     * @param menu
     * @return
     */
    @Override
    public int updateMenu(BlogMenu menu) {
        LoginUserVo loginUserVo = BlogSecurityUtil.get(SecurityConstants.LOGIN_USER, LoginUserVo.class);
        String username = loginUserVo.getUsername();
        menu.setUpdateBy(username);
        menu.setUpdateTime(new Date());
        return blogMenuMapper.updateMenu(menu);
    }

    /**
     * 获取全部菜单信息
     *
     * @return
     */
    @Override
    public List<BlogMenu> getBlogMenuList(BlogMenu blogMenu) {
        return blogMenuMapper.getBlogMenuList(blogMenu);
    }

    /**
     * 逻辑删除菜单
     *
     * @param id
     * @return
     */
    @Override
    @Transactional
    public int deleteMenu(Long id) {
        int i = blogMenuMapper.deleteMenuById(id);
        deleteMenuRecursion(id);
        return i;
    }

    /**
     * 递归删除当前目录下的子菜单
     * @param id
     * @return
     */
    private void deleteMenuRecursion(Long id){
        List<BlogMenu> blogMenuList = blogMenuMapper.getBlogMenuByParentIdToDelete(id);
        if (blogMenuList.size() > 0){
            for (BlogMenu blogMenu : blogMenuList) {
                blogMenuMapper.deleteMenuById(blogMenu.getId());
                deleteMenuRecursion(blogMenu.getId());
            }
        }
    }

    /**
     * 获取全部菜单id
     * @return
     */
    @Override
    public List<Long> getMenuIdAll() {
        return blogMenuMapper.getMenuIdAll();
    }

    private MenuSelectVo buildMenuSelectVo(BlogMenu blogMenu) {
        MenuSelectVo menuSelectVo = new MenuSelectVo();
        menuSelectVo.setParentId(blogMenu.getParentId().toString());
        menuSelectVo.setValue(blogMenu.getId().toString());
        menuSelectVo.setLabel(blogMenu.getMenuName());
        menuSelectVo.setId(blogMenu.getId().toString());
        return menuSelectVo;
    }

    /**
     * 获取子节点
     *
     * @param ids
     * @return
     */
    public Map<Long, Boolean> hasChildrenData(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return Collections.emptyMap();
        }


        List<Long> menuPids = blogMenuMapper.hasChildrenData(ids);
        Map<Long, Boolean> map = menuPids.stream()
                .collect(Collectors.toMap(id -> id, id -> Boolean.TRUE));

        ids.forEach(id -> {
            if (!map.containsKey(id)) {
                map.put(id, Boolean.FALSE);
            }
        });

        return map;
    }

    /**
     * 初始化路由
     *
     * @param blogMenu 菜单节点
     * @return
     */
    public static RouterVo initRouterVo(BlogMenu blogMenu) {
        RouterVo routerVo = new RouterVo();
        routerVo.setName(StringUtils.capitalize(blogMenu.getPath()));

        if ("M".equals(blogMenu.getMenuType()) && StringUtils.isEmpty(blogMenu.getComponent())) {
            routerVo.setComponent("Layout");
            routerVo.setRedirect("noRedirect");
            routerVo.setPath("/" + blogMenu.getPath());
        } else {
            routerVo.setComponent(blogMenu.getComponent());
            routerVo.setPath(blogMenu.getPath());
        }
        if (blogMenu.getVisible() == 0) {
            routerVo.setHidden(false);
        } else {
            routerVo.setHidden(true);
        }
        // 配置路由额外信息
        MetaVo metaVo = new MetaVo();
        metaVo.setIcon(blogMenu.getIcon());
        metaVo.setTitle(blogMenu.getMenuName());
        routerVo.setMeta(metaVo);
        return routerVo;
    }
//
//    /**
//     * 构建树形目录
//     * @param blogMenu
//     * @param blogMenuListAll
//     * @return
//     */
//    public BlogMenu buildTreeMenu(BlogMenu blogMenu, List<BlogMenu> blogMenuListAll){
//        for (BlogMenu menu : blogMenuListAll) {
//            if (blogMenu.getId().intValue() == menu.getParentId().intValue()){
//                blogMenu.getChildren().add(menu);
//                this.buildTreeMenu(menu, blogMenuListAll);
//            }
//        }
//        return blogMenu;
//    }


//    /**
//     * 构建包含子节点的路由
//     *
//     * @param blogMenu
//     * @return
//     */
//    public RouterVo convertToRouterVo(BlogMenu blogMenu) {
//        RouterVo routerVo = new RouterVo();
//        routerVo.setName(StringUtils.capitalize(blogMenu.getPath()));
//        routerVo.setPath(blogMenu.getPath());
//        if (blogMenu.getVisible() == 0) {
//            routerVo.setHidden(false);
//        }
////        routerVo.setRedirect(b);
//        routerVo.setComponent(blogMenu.getComponent());
//        // 配置路由额外信息
//        MetaVo metaVo = new MetaVo();
//        metaVo.setIcon(blogMenu.getIcon());
//        metaVo.setTitle(blogMenu.getMenuName());
//        routerVo.setMeta(metaVo);
//
//        List<BlogMenu> children = blogMenu.getChildren();
//        ArrayList<RouterVo> routerVos = new ArrayList<>();
//        // 构建子节点
//        if (children.size() > 0) {
//            for (int i = 0; i < children.size(); i++) {
//                RouterVo childrenRouterVo = this.convertToRouterVo(children.get(i));
//                routerVos.add(childrenRouterVo);
//            }
//            routerVo.setChildren(routerVos);
//            routerVo.setAlwaysShow(true);
//        } else {
//            routerVo.setAlwaysShow(false);
//        }
//        return routerVo;
//    }


//    /**
//     * 转换成前端路由
//     *
//     * @param blogMenuList
//     * @return
//     */
//    private List<RouterVo> convertToRouterVoList(List<BlogMenu> blogMenuList) {
//        List<RouterVo> routerVoList = new ArrayList<>();
//        for (BlogMenu blogMenu : blogMenuList) {
//            RouterVo routerVo = this.convertToRouterVo(blogMenu);
//            routerVoList.add(routerVo);
//        }
//
//        return routerVoList;
//    }


    public static void main(String[] args) throws InvocationTargetException, IllegalAccessException {
        BlogMenu blogMenu = new BlogMenu();
        blogMenu.setId(100l);
        blogMenu.setMenuName("111");
        blogMenu.setMenuType("1111");
        blogMenu.setParentId(1L);
        blogMenu.setComponent("11111");
        blogMenu.setPath("111");
        RouterVo routerVo = new RouterVo();
        BeanUtils.copyProperties(routerVo, blogMenu);
        System.out.println(routerVo);
    }
}
